package com.joyoung.sweep.utils.blue;

import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.TextUtils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;

public class LinkerUtils {

    public static boolean isBlank(String ssid) {
        return TextUtils.isEmpty(ssid) || ssid.trim().isEmpty();
    }

    public static boolean isEmptySsid(String ssid) {

        if (isBlank(ssid)) {
            return true;
        }

        return getPureSsid(ssid).toLowerCase().contains("<unknown ssid>");
    }

    public static boolean isEmptyBssid(String bssid) {

        if (isBlank(bssid)) {
            return true;
        }

        bssid = bssid.trim();
        return bssid.equals("000000000000") || bssid.equals("00-00-00-00-00-00") || bssid.equals("00:00:00:00:00:00");
    }

    public static String getSsid(Context context, int networkId) {

        if (networkId != -1) {

            WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            List<WifiConfiguration> wifiConfigurations = wifiManager.getConfiguredNetworks();
            if (wifiConfigurations == null) {
                return null;
            }

            for (WifiConfiguration wifiConfiguration : wifiConfigurations) {
                if (wifiConfiguration.networkId == networkId) {
                    return wifiConfiguration.SSID;
                }
            }
        }

        return null;
    }

    public static String getBssid(Context context, int networkId) {

        if (networkId != -1) {

            WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            List<WifiConfiguration> wifiConfigurations = wifiManager.getConfiguredNetworks();
            if (wifiConfigurations == null) {
                return null;
            }

            for (WifiConfiguration wifiConfiguration : wifiConfigurations) {
                if (wifiConfiguration.networkId == networkId) {
                    return wifiConfiguration.BSSID;
                }
            }
        }

        return null;
    }

    public static String getPureSsid(String ssid) {

        if (isBlank(ssid)) {
            return ssid;
        }

        if (ssid.startsWith("\"")) {
            ssid = ssid.substring(1);
        }
        if (ssid.endsWith("\"")) {
            ssid = ssid.substring(0, ssid.length() - 1);
        }

        return ssid;
    }

    /**
     * Convert a IPv4 address from an integer to an InetAddress.
     *
     * @param hostAddress an int corresponding to the IPv4 address in network byte order
     */
    public static InetAddress intToInetAddress(int hostAddress) {
        byte[] addressBytes = {(byte) (0xff & hostAddress), (byte) (0xff & (hostAddress >> 8)), (byte) (0xff & (hostAddress >> 16)), (byte) (0xff & (hostAddress >> 24))};

        try {
            return InetAddress.getByAddress(addressBytes);
        } catch (UnknownHostException e) {
            throw new AssertionError();
        }
    }

    /**
     * Convert a IPv4 address from an InetAddress to an integer
     *
     * @param inetAddr is an InetAddress corresponding to the IPv4 address
     * @return the IP address as an integer in network byte order
     */
    public static int inetAddressToInt(InetAddress inetAddr) throws IllegalArgumentException {
        byte[] addr = inetAddr.getAddress();
        return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) | ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
    }

    public static String calculateIpAddress(int ipAddress) {
        return (ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "." + (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff);
    }

    public static int edgeInt(int data, int min, int max) {

        if (data > max) {
            data = max;
        } else if (data < min) {
            data = min;
        }

        return data;
    }

    public static byte[] int2bytes(int data) {

        byte[] datas = new byte[4];
        datas[0] = ((byte) ((data & 0xFF000000) >> 24));
        datas[1] = ((byte) ((data & 0xFF0000) >> 16));
        datas[2] = ((byte) ((data & 0xFF00) >> 8));
        datas[3] = ((byte) (data & 0xFF));

        return datas;
    }

    public static int[] bytes2ints(byte[] datas) {

        if (datas == null) {
            return null;
        }

        int length = datas.length;
        if (length == 0) {
            return new int[0];
        }

        IntBuffer buffer = ByteBuffer.wrap(datas).asIntBuffer();
        int[] out = new int[buffer.remaining()];
        buffer.get(out);

        return out;
    }

    public static String bytes2HexString(byte[] datas) {
        return bytes2HexStringWithSplit(datas, "");
    }

    public static String bytes2HexStringWithWhitespace(byte[] datas) {
        return bytes2HexStringWithSplit(datas, " ");
    }

    public static String bytes2Characters(byte[] datas) {

        StringBuilder sb = new StringBuilder();
        for (byte b : datas) {
            sb.append((char) b);
        }
        return sb.toString();
    }

    public static int byte2Int(byte data) {
        return data & 0xFF;
    }

    public static String bytes2HexStringWithSplit(byte[] datas, String splitString) {

        if (datas == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        String format = "%02X";

        for (int i = 0; i < datas.length; i++) {
            sb.append(String.format(format, datas[i] & 0xFF));
            if (i < datas.length - 1) {
                sb.append(splitString);
            }
        }

        return sb.toString();
    }

    public static List<String> bytes2HexStrings(List<byte[]> data) {

        if (data == null) {
            return null;
        }

        if (data.isEmpty()) {
            Collections.emptyList();
        }
        ArrayList<String> hexes = new ArrayList<>();
        for (byte[] item : data) {
            hexes.add(bytes2HexString(item));
        }

        return hexes;
    }

    public static boolean isByteEquals(byte data1, int data2) {
        return (data1 & 0xFF) == data2;
    }

    public static boolean isHexString(String hexString) {
        return isHexStringWithSplit(hexString, "");
    }

    public static boolean isHexStringWithWhitespace(String hexString) {
        return isHexStringWithSplit(hexString, " ");
    }

    public static boolean isHexStringWithSplit(String hexString, String splitString) {

        if (hexString == null) {
            return false;
        }

        if (splitString != null) {
            hexString = hexString.replaceAll(splitString, "");
        }
        if (hexString.length() % 2 != 0) {
            return false;
        }

        Pattern pattern = Pattern.compile("([0-9]|[a-f]|[A-F]){2}");
        int size = hexString.length() / 2;
        for (int i = 0; i < size; i++) {
            if (!pattern.matcher(hexString.substring(i * 2, (i + 1) * 2)).matches()) {
                return false;
            }
        }

        return true;
    }

    public static byte[] hexStringWithSplit2bytes(String hexString, String split) {

        if (!isHexStringWithSplit(hexString, split)) {
            return null;
        }

        hexString = hexString.replaceAll(split, "");
        int size = hexString.length() / 2;
        byte[] array = new byte[size];
        for (int i = 0; i < size; i++) {
            array[i] = (byte) Integer.valueOf(hexString.substring(i * 2, (i + 1) * 2), 16).intValue();
        }

        return array;
    }

    public static byte[] hexStringWithWhitespace2bytes(String hexString) {
        return hexStringWithSplit2bytes(hexString, " ");
    }

    public static byte[] hexString2bytes(String hexString) {
        return hexStringWithSplit2bytes(hexString, "");
    }

    public static NetworkInterface getNetworkInterface(String ip) {

        if (TextUtils.isEmpty(ip)) {
            return null;
        }

        try {

            Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces();
            if (enumeration == null) {
                return null;
            }

            while (enumeration.hasMoreElements()) {

                NetworkInterface networkInterface = enumeration.nextElement();
                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
                if (inetAddresses != null) {

                    while (inetAddresses.hasMoreElements()) {

                        if (ip.equalsIgnoreCase(inetAddresses.nextElement().getHostAddress())) {
                            return networkInterface;
                        }
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static String getPureMac(String mac) {

        if (mac == null) {
            return mac;
        }

        String[] toReplaces = new String[]{":", "-", "_", " "};
        for (String toReplace : toReplaces) {
            mac = mac.replaceAll(toReplace, "");
        }
        return mac.trim();
    }

    public static String toMac(String address) {

        if (address == null) {
            return null;
        }

        address = address.toUpperCase(Locale.US);

        String regex1 = "[0-9A-F]{2}(:[0-9A-F]{2}){5}$";
        String regex2 = "[0-9A-F]{2}(-[0-9A-F]{2}){5}$";
        String regex3 = "[0-9A-F]{2}([0-9A-F]{2}){5}$";

        if (Pattern.matches(regex1, address)) {
            return address;
        }

        if (Pattern.matches(regex2, address)) {
            return address.replaceAll("-", ":");
        }

        if (Pattern.matches(regex3, address)) {
            StringBuilder stringBuffer = new StringBuilder();

            int length = address.length() / 2;
            for (int i = 0; i < length; i++) {
                stringBuffer.append(address.substring(2 * i, 2 * i + 2));
                if (i < length - 1) {
                    stringBuffer.append(":");
                }
            }

            return stringBuffer.toString();
        }

        return null;
    }

    public static String calculateHFModuleMacByBSSID(String bssid) throws Exception {
        Long number = Long.valueOf(getPureMac(bssid), 16);
        number -= 1;
        return String.format("%012X", number);
    }
}
